// convert Google Maps into an AMD module
// as described here: http://blog.millermedeiros.com/requirejs-2-0-delayed-module-evaluation-and-google-maps/
define('Gmaps', ['async!http://maps.google.com/maps/api/js?v=3&key=AIzaSyDLlX5zUfVSffJkvA6BguW4xkT_m9hKjAs&language='+ window.vta.settings.language +'&sensor=false'],
function(){
    
    
    // set some default values
//    window.vta.maps.standard.latitude = 52.0178; // 37.4419, 
//    window.vta.maps.standard.longitude = 5.0401; // -122.1419
//    window.vta.maps.standard.zoom = 16;
//    window.vta.maps.standard.mapTypeId = google.maps.MapTypeId.ROADMAP;
//    
//    window.vta.maps.coords = { 'latitude': 0, 'longitude': 0 };
//    
//    window.vta.maps.geocoder = new google.maps.Geocoder();
    
    
    
    /**
     * Class vta.geo
     * Custom class for programming all things geo (like Google Maps or locations).
     * 
     * @author      Jeroen Sen <jeroensen@22vision.nl>
     * @version     20120920
     * 
     */
    window.vta.geo = function() {
        
        // Google Map Object
        this.map = {};
        
        this.latitude = 52.0178;
        this.longitude = 5.0401;
        this.LatLng = new google.maps.LatLng(this.latitude, this.longitude);
        
        this.zoom = 16;
        
        this.mapType = google.maps.MapTypeId.ROADMAP;
        
        this.geocoder = new google.maps.Geocoder();
        this.geocoderCallback = null;
        
        this.markers = { current: {} };
        
        
        
        /**
         * function getLatLng
         * Will convert the parameter Number latitude and longitude into a google.maps.LatLng object.
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20120920
         * @param       Number latitude
         * @param       Number longitude
         * @return      google.maps.LatLng this.LatLng
         * 
         */
        this.getLatLng = function(latitude, longitude) {
            
            return new google.maps.LatLng(latitude, longitude);
            
        } // this.getLatLng = function(latitude, longitude)
        
        
        
        /**
         * function addMarker
         * Will add a google.maps.Marker marker based on the location identified by parameter google.maps.LatLng LatLng. 
         * The created marker will be returned.
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20120920
         * @param       google.maps.LatLng LatLng
         * @param       String text, the title of the marker
         * @return      google.maps.Marker marker
         * 
         */
        this.addMarker = function(LatLng, options, callback) {
        
            var self = this;
            var callback = callback;
            var options = $.extend({ position: LatLng }, options);
//            var marker = new google.maps.Marker({ position: LatLng, title: text });
            var marker = new google.maps.Marker(options);
            
            marker.setMap(this.map);
            
            
            
            // add the event listener for dragging that beast
            google.maps.event.addListener(marker, 'dragend', function(){
                self.geoCode({ 'location': marker.getPosition(), 'partialmatch': true }, callback, 'all');
            });
            
            return marker;
            
        } //this.addMarker = function(LatLng, text)
        
        
        
        /**
         * 
         * 
         */
        this.updateMarkerPosition = function(marker, LatLng) {
console.log('updateMarkerPosition');
console.log(marker.getPosition());
            
        } // this.updateMarkerPosition = function(latLng)
        
        
        
        /**
         * function getMarker
         * Will look into the stack of markers to get the marker identified by String parameter key. When found, 
         * return it.
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20120921
         * @param       String key
         * @return      google.maps.Marker marker
         * 
         */
        this.getMarker = function(key) {
            
            var marker = null;
            
            try {
                
                marker = this.markers[key];
                
            } catch (e) {
                // do nothing
                console.log(e);
            }
            
            return marker;
            
        } // this.getMarker = function(key)
        
        
        
        /**
         * 
         * 
         */
        this.getMarkerLocation = function(key) {
console.log("getMarkerLocation");            
            var marker = this.getMarker(key);
            
            var LatLng = marker.getPosition();
console.log(LatLng);
            
            var test = this.geoCode({ 'location': LatLng, 'partialmatch': true }, null, 'all');

console.log(test);            
            
        } // this.getMarkerLocation = function(key)
        
        
        
        /**
         * function createMap
         * Will create a Google Maps object and attatch it to the parameter String divName. When
         * the values of latitude and longitude are not set, the standard VTA values will be used.
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20120919
         * @param       String divName, the name of the div to which the Map Object should be attatched
         * @param       Number latitude, the latitude in which the map will center
         * @param       Number longitude, the longitude in which the map will center
         * @return      Google Maps Object map
         * 
         */
        this.createMap = function(divName, latitude, longitude) {
            
            if (latitude == undefined || typeof latitude != "number") {
                var latitude = this.latitude;
            }
    
            if (longitude == undefined || typeof longitude != "number") {
                var longitude = this.longitude;
            }
            
            var mapDiv = document.getElementById(divName);

            this.map = new google.maps.Map(mapDiv, {
                center: this.getLatLng(latitude, longitude),
                zoom: this.zoom,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            });
            
            return this.map;
            
        } // this.createMap = function(divName, latitude, longitude)
        
        
        
        /**
         * function setMarkerLocationByAddress
         * Will take a google.maps.Marker marker and a textual address and place the marker on the given address. The marker will
         * be centered on the map.
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20120925
         * @param       String address
         * @param       google.maps.Marker marker
         * @return      void
         * 
         */
        this.setMarkerLocationByAddress = function(address, marker, callback) {

            var self = this;

            // check is address is set, string length
            if (typeof address == "string" && address.toString().length > 0) {
             
                // convert to a LatLng object
                this.geoCode({ 'address': address, 'partialmatch': true }, marker, 'latlng');
                
                if (typeof callback == "function") {
                    this.geoCode({ 'address': address, 'partialmatch': true }, callback, 'all');
                }
                
            }
            
        } // this.setLocationByAddress = function(address)
        
        
        
        /**
         * function setMarkerLocationByCoords
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20120925
         * @param       Float latitude
         * @param       Float longitude
         * @param       google.maps.Marker marker
         * @return      void
         * 
         */
        this.setMarkerLocationByCoords = function(latitude, longitude, marker, callback) {
            
            if (marker instanceof google.maps.Marker) {
                
                var latlng = this.getLatLng(latitude, longitude);
                
                marker.setPosition(latlng);
                this.map.panTo(latlng);
                
                if (typeof callback == "function") {
                    this.geoCode({ 'location': latlng, 'partialmatch': true }, callback, 'all');
                }
                
            } // if (marker instanceof google.maps.Marker)
            
        } // this.setMarkerLocationByCoords = function(latitude, longitude, marker)
        
        
        
        /**
         * function setCurrentLocation
         * Will set the latitude and longitude coords of the current location to the custom global google.maps.coords object.
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20120918
         * @param       Number latitude
         * @param       Number longitude
         * @return      void
         * 
         */
        this.setCurrentLocation = function(latitude, longitude, callbackCoords, callbackMarker, center) {

            if ((typeof latitude == "number" && latitude > 0) && (typeof longitude == "number" && longitude > 0)) {
                $('.top-right').notify({ message: { html: 'De huidige positie is succesvol bepaald.' }, type: 'success' }).show();
                this.latitude = latitude;
                this.longitude = longitude;
                
                if (center != undefined && center == true) {
                    this.panMap(latitude, longitude, callbackMarker);
                }

                if (callbackCoords != undefined && typeof callbackCoords == "function") {
                    callbackCoords.call(this, { 'latitude': this.latitude, 'longitude': this.longitude });
                }
                
            } else {
                $('.top-right').notify({ message: { html: 'De huidige positie is <u>niet</u> bepaald.' }, type: 'danger' }).show();
            }
            
        } // this.setCurrentLocation(latitude, longitude)
        
        
        
        /**
         * function retrieveCurrentLocationAsText
         * Will request a textual representation of the given address identified by Number parameters latitude and longitude.
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20120920
         * @param       Number latitude
         * @param       Number longitude
         * @param       function callback
         * @return      void
         * 
         */
        this.retrieveCurrentLocationAsText = function(latitude, longitude, callback) {
            
            if ((typeof latitude == "number" && latitude > 0) && (typeof longitude == "number" && longitude > 0)) {
                
                var LatLng = new google.maps.LatLng(latitude, longitude);
                
                this.geoCode({ 'location': LatLng, 'partialmatch': true }, callback, 'text');

            }
            
        } // this.retrieveCurrentLocationAsText = function(latitude, longitude, center, callback)
        
        
        
        /**
         * function retrieveCurrentLocationAsObject
         * 
         * 
         */
        this.retrieveCurrentLocationAsObject = function(latitude, longitude, callback) {

            if ((typeof latitude == "number" && latitude > 0) && (typeof longitude == "number" && longitude > 0)) {

                var LatLng = new google.maps.LatLng(latitude, longitude);

                this.geoCode({ 'location': LatLng, 'partialmatch': true }, callback, 'all');

            }
            
        } //this.retrieveCurrentLocationAsObject = function(latitude, logitude, callback) 
        
        
        
        /**
         * function getCurrentLocation
         * Will return the coords of the current location when set.
         * 
         * @author      Jeroen Sen <jeroensen@2vision.nl>
         * @version     20120918
         * @param       void
         * @return      Object containing the latitude and longitude of the current location
         * 
         */
        this.getCurrentLocation = function() {
        
            return { 'latitude': this.latitude, 'longitude': this.longitude };
            
        } // this.getCurrentLocation = function()
        
        
        
        /**
         * function retrieveCurrentLocation
         * Will retrieve the current location based on the native navigator.geolocation object.
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20120920
         * @param       void
         * @return      void
         * 
         */
        this.retrieveCurrentLocation = function(callback, center) {

            var self = this;
            var callbackCoords = null;
            var callbackText = null;
            
            if (center == undefined) {
                var center = false;
            }
         
            if (typeof callback.coords == "function") {
                callbackCoords = callback.coords;
            }
            
            if (typeof callback.text == "function") {
                callbackText = callback.text;
            }
            
            if (typeof callback.marker == "function") {
                callbackMarker = callback.marker;
            }

            
            try {

                if (navigator.geolocation) {
    
                    navigator.geolocation.getCurrentPosition( 
     
                        function (position) {  
    
                            // Did we get the position correctly?
                            // alert (position.coords.latitude);
        
                            // To see everything available in the position.coords array:
                            // for (key in position.coords) {alert(key)}

                            
                            self.setCurrentLocation(position.coords.latitude, position.coords.longitude, callbackCoords, callbackMarker, center);
//                            self.retrieveCurrentLocationAsText(position.coords.latitude, position.coords.longitude, callbackText, center);
                            self.retrieveCurrentLocationAsObject(position.coords.latitude, position.coords.longitude, callbackText, center);
                            
                        }, 
    
                        // next function is the error callback
                        function (error) {
                            
                            switch(error.code) {
                                case error.TIMEOUT:
                                    $('.top-right').notify({ message: { html: 'Het duurt te lang om de positie te bepalen, geef deze handmatig in.' }, type: 'danger' }).show();
    //                                alert ('Timeout');
                                    break;
                                case error.POSITION_UNAVAILABLE:
    //                                alert ('Position unavailable');
                                    $('.top-right').notify({ message: { html: 'Het is op dit moment niet mogelijk de huidige positie te bepalen.' }, type: 'danger' }).show();
                                    break;
                                case error.PERMISSION_DENIED:
                                    $('.top-right').notify({ message: { html: 'U heeft niet voldoende rechten om de huidige positie te bepalen.' }, type: 'danger' }).show();
    //                                alert ('Permission denied');
                                    break;
                                case error.UNKNOWN_ERROR:
    //                                alert ('Unknown error');
                                    $('.top-right').notify({ message: { html: 'Er heeft zich een onbekende fout voorgedaan, probeer het nogmaals.' }, type: 'danger' }).show();
                                    break;
                            }
                        },
                        
                        {
                            maximumAge:30000,
                            timeout:15000
                        }
                        
                    );
                }
    
            } catch (e) {
                // for now, do nothing
                console.log(e);
            }
            
        } // this.retrieveCurrentLocation = function()
        
        
        
        /**
         * function centerMap
         * Will center the map to the given Number parameters latitude and longitude.
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20120920
         * @param       Number latitude
         * @param       Number longitude
         * @return      void
         * 
         */
        this.centerMap = function(latitude, longitude) {
            
            this.map.setCenter(this.getLatLng(latitude, longitude));
            
        } //this.centerMap = function(latitude, longitude)
        
        
        
        /**
         * function panMap
         * Will animate the transition of the map to the given Number parameters latitude and longitude and place a google.maps.Marker on the map.
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20120920
         * @param       Number latitude
         * @param       Number longitude
         * @return      void
         * 
         */
        this.panMap = function(latitude, longitude, callback) {
            
            this.map.panTo(this.getLatLng(latitude, longitude));
            
            this.map.setZoom(18);
            
            this.markers.current = this.addMarker(this.getLatLng(latitude, longitude), { title: 'huidige positie', draggable: true }, callback);
            
            
        } //this.panMap = function(latitude, longitude)
        
        
        
        /**
         * function geoCode
         * Will convert the request object (containing a LatLng object) to a geocode object and pass it to member function
         * geoCodeResult which will execute the callback.
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20120920
         * @param       google.maps.GeocoderRequest request
         * @param       function callback
         * @param       String type, the type of return information from the geocode object
         * @return      void
         * 
         */
        this.geoCode = function(request, callback, type) {

            var self = this;
            
            // ask Google for the geocode result and return it to the 
            this.geocoder.geocode(request, function(callback, type, self) {
                
                return(function(results, status){
                    
                    if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
                        
                        var data = null;
                        
                        switch(type) {
                            case 'text':
                                data = results[0].formatted_address;
                                break;
                            case 'latlng':
                                data = new google.maps.LatLng(results[0].geometry.location.lat(), results[0].geometry.location.lng());
//                                data = result[0].geometry.location;
                                break;
                            case 'all':
                            case 'object':
                            default:
                                data = results[0];
                                break;
                        }
//console.log(results[0].geometry.location);
//console.log(results[0].geometry.location.lat()); 
//console.log(results[0].geometry.location.lng());
//console.log(data);
//console.log(callback);
                        self.geoCodeResult(data, callback);
                                              
                    }
                });
                
            }(callback, type, this));

        } // this.geoCode = function()
        
        
        
        /**
         * function geoCodeResult
         * Will execute the callback and pass the result to it.
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20120921
         * @param       google.maps.GeocoderResult result
         * @param       function callback
         * @return      void
         * 
         */
        this.geoCodeResult = function(result, callback) {

            if (callback instanceof google.maps.Marker) {
                callback.setPosition(result);
                this.map.panTo(result);
            } else if (callback == null) {
                return result;
            } else {
                callback.call(this, result);
            }
            
        } // this.geoCodeResult = function(result, callback)
        
        
        
        /**
         * function parseLocation
         * Will retrieve a cetain part of a formatted location object.
         * 
         * @author      Jeroen Sen <jeroensen@22vision.nl>
         * @version     20121030
         * @param       Object location
         * @param       String component
         * @return      String
         * 
         */
        this.parseLocation = function(location, component) {

            for (var n in location.address_components) {

                if ($.inArray(component, location.address_components[n].types) != -1) {
                    return location.address_components[n].long_name;
                }
                
            }
            
        } // this.parseLocation = function(location, component)
        
        
        
    } // window.vta.maps = function()
    
    
    
    // return the gmaps namespace for brevity
    return window.google.maps;
    
});